

<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=auto>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/img/favicon.png">
  <link rel="icon" href="/img/favicon.png">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="description" content="Blue~u~u~u">
  <meta name="author" content="Blue~u~u~u">
  <meta name="keywords" content="">
  <meta name="description" content="Lock 底层原理探究第一节 JMMTIP  为什么要学这个 JMM？ 答：为了理解 volatile 关键词。  为什么要学这个 volatile ？ 答：因为 volatile 是后面整个技术体系的基石之一。    1、名词解释JMM 是 Java Memory Model 的缩写，意思是：Java 内存模型。 2、产生背景①高速缓存现代计算机 CPU 的运算处理能力比内存 I&#x2F;O 读写能力高">
<meta property="og:type" content="article">
<meta property="og:title" content="JUC学习笔记（五）Lock底层原理探究">
<meta property="og:url" content="http://www.slx.blue/2022/03/10/JUC05-LockPrinciple/index.html">
<meta property="og:site_name" content="Blue~u~u~u~u">
<meta property="og:description" content="Lock 底层原理探究第一节 JMMTIP  为什么要学这个 JMM？ 答：为了理解 volatile 关键词。  为什么要学这个 volatile ？ 答：因为 volatile 是后面整个技术体系的基石之一。    1、名词解释JMM 是 Java Memory Model 的缩写，意思是：Java 内存模型。 2、产生背景①高速缓存现代计算机 CPU 的运算处理能力比内存 I&#x2F;O 读写能力高">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-01.png?versionId=CAEQKRiBgIC_27LH.xciIDgzNmIyNzk2NDAxOTQzNTFiMDQ5NDk0ODE0YjQxOTk1">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-02.png?versionId=CAEQKRiBgIC827LH.xciIDIyODVhZmNiYmEwYjQ0ZTU4ZDZlMGI3MDZiYjU3Y2M0">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-03.png?versionId=CAEQKRiBgIC627LH.xciIGNkMmQwMGM2NmNhMDQ5OTc4YTYzNzc4Mzk5NWFkNzdh">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-04.png?versionId=CAEQKRiBgMC227LH.xciIDYwMmMxNTU2NWM3NDRjYjJiYTUxZmVmMDY0ZWU2Mzkz">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-05.png?versionId=CAEQKRiBgMCx27LH.xciIGQ4OTI0ZGY2M2U2MDRkMzJhNTlmODcyMmVkM2UyMzYw">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-06.png?versionId=CAEQKRiBgMCu27LH.xciIDIzYjM0MTNmODMxZjRhNWE4YjRmYTgzM2EwYmFhYzcx">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-07.png?versionId=CAEQKRiBgID.2bLH.xciIDRmOGI0YTc0NmJlMTQwNTliZWNiNGI2MGJiMzBjOTA4">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-08.png?versionId=CAEQKRiBgID72bLH.xciIDI0ODFjODMwYjY3ZTRkNTE4OTZlZDY0ZGE1Nzg1MmFk">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-09.png?versionId=CAEQKRiBgID62bLH.xciIDMxOTJkNjQ5YWFhYjQ0OWJhNzg4NjJiNTYzNjMyODU5">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-10.png?versionId=CAEQKRiBgMD42bLH.xciIGI2Y2IxMjhhNzIwZDQ5YjZhNTJmZWI5NzgyYTE5YjYw">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-11.png?versionId=CAEQKRiBgMDo2bLH.xciIGZmNDhiMDgxYTE1NzQwZGY5YzcxN2RmMDRmZDMwYjJk">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-12.png?versionId=CAEQKRiCgMDq2bLH.xciIDliN2ZiOWM2NGZmMTQ4OTFiNmFiNDVlZjBmM2QwNWU2">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-13.png?versionId=CAEQKRiBgMDn2bLH.xciIDRhZmZiMmFkNjI3MTRjODI4ZDNiYTYxMTJkYTE0MzA4">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-14.png?versionId=CAEQKRiCgIDk2bLH.xciIGViNjZhNjkxYjNkZjQxY2Y4MWEzOTdhYWY4NjJmYjIz">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-15.png?versionId=CAEQKRiBgIDh2bLH.xciIDVjZmJlYmU0MDIwNzRhOGViYmUyNTZhYzYxMWJlNDgx">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-16.png?versionId=CAEQKRiBgIDd2bLH.xciIDhlZjQzYmM5MDk0ZDRmZGY4Zjg0MzE5MmM1ZDkyOWE2">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-17.png?versionId=CAEQKRiBgMCn2LLH.xciIDE0ZDYyNGMyNzYxNzQ0MzY5OTRmYTcwMjE0YjdjM2U5">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-18.png?versionId=CAEQKRiBgICn2LLH.xciIDY4ZjQ1MDRmZjBmMzRhNDlhZTlhZjUwMmU1NGUxOTkz">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-19.png?versionId=CAEQKRiBgMCh2LLH.xciIGFmNDU5ZTVmZjY2ZTRmNDdhOWZlYzExNWE3Y2MyMmY0">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-20.png?versionId=CAEQKRiCgMCO2LLH.xciIDYxMTI3NzBiY2JjZTRlZjJhNzIxMjExMDAxNzViZDM4">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-21.png?versionId=CAEQKRiBgMCG2LLH.xciIGE4MmVjMTBhMzk5OTQ0NGE4Y2ViMjQyYWViYTMyMGNj">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-22.png?versionId=CAEQKRiBgICG2LLH.xciIGZmMDAwY2U4NWJlMTQ4ZjRhNmMzZGFjOTkxOWVlOGRk">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-23.png?versionId=CAEQKRiBgICL2LLH.xciIGJlM2RlMDQwZGFmODQxZWFhNjlkMTA1YTEwMjc4YjU3">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-24.png?versionId=CAEQKRiBgICN2LLH.xciIGM5ZTA1MDJhMTMzMDQ1ODQ5Y2M2NTg0YTBjNGEzZmI0">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-25.png?versionId=CAEQKRiBgMD017LH.xciIDhiNjk4YjhkNzU4NTRjOGFhZWZlNDcyMTI0NzYyYzZi">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-26.png?versionId=CAEQKRiBgMCF2LLH.xciIDUzOTgzNDU4YzZjMDQ3OGRiNzc4YjhmYTI0YTA1NjE5">
<meta property="article:published_time" content="2022-03-10T03:39:29.000Z">
<meta property="article:modified_time" content="2022-03-10T03:41:09.905Z">
<meta property="article:author" content="Blue~u~u~u">
<meta property="article:tag" content="JUC">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-01.png?versionId=CAEQKRiBgIC_27LH.xciIDgzNmIyNzk2NDAxOTQzNTFiMDQ5NDk0ODE0YjQxOTk1">
  
  <title>JUC学习笔记（五）Lock底层原理探究 - Blue~u~u~u~u</title>

  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4/dist/css/bootstrap.min.css" />


  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/github-markdown-css@4/github-markdown.min.css" />
  <link  rel="stylesheet" href="/lib/hint/hint.min.css" />

  
    
    
      
      <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js@10/styles/github-gist.min.css" />
    
  

  
    <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3/dist/jquery.fancybox.min.css" />
  


<!-- 主题依赖的图标库，不要自行修改 -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_ba1fz6golrf.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_kmeydafke9r.css">


<link  rel="stylesheet" href="/css/main.css" />

<!-- 自定义样式保持在最底部 -->


  <script id="fluid-configs">
    var Fluid = window.Fluid || {};
    var CONFIG = {"hostname":"www.slx.blue","root":"/","version":"1.8.12","typing":{"enable":true,"typeSpeed":180,"cursorChar":"_","loop":true},"anchorjs":{"enable":true,"element":"h1,h2,h3,h4,h5,h6","placement":"right","visible":"hover","icon":""},"progressbar":{"enable":true,"height_px":3,"color":"#29d","options":{"showSpinner":false,"trickleSpeed":100}},"copy_btn":true,"image_zoom":{"enable":true,"img_url_replace":["",""]},"toc":{"enable":true,"headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":0},"lazyload":{"enable":true,"loading_img":"/img/loading.gif","onlypost":false,"offset_factor":2},"web_analytics":{"enable":false,"baidu":null,"google":null,"gtag":null,"tencent":{"sid":null,"cid":null},"woyaola":null,"cnzz":null,"leancloud":{"app_id":null,"app_key":null,"server_url":null,"path":"window.location.pathname"}},"search_path":"/local-search.xml"};
  </script>
  <script  src="/js/utils.js" ></script>
  <script  src="/js/color-schema.js" ></script>
<meta name="generator" content="Hexo 5.4.0"></head>

<script src="https://cdn.jsdelivr.net/npm/jquery/dist/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/font-awesome/css/font-awesome.min.css"/>
<script src="/live2d-widget/autoload.js"></script>


<body>
  <header style="height: 70vh;">
    <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand" href="/">
      <strong>Blue~u~u</strong>
    </a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/">
                <i class="iconfont icon-home-fill"></i>
                首页
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/archives/">
                <i class="iconfont icon-archive-fill"></i>
                归档
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/categories/">
                <i class="iconfont icon-category-fill"></i>
                分类
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/tags/">
                <i class="iconfont icon-tags-fill"></i>
                标签
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/about/">
                <i class="iconfont icon-user-fill"></i>
                关于
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/links/">
                <i class="iconfont icon-link-fill"></i>
                友链
              </a>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" target="_self" href="javascript:;" data-toggle="modal" data-target="#modalSearch" aria-label="Search">
              &nbsp;<i class="iconfont icon-search"></i>&nbsp;
            </a>
          </li>
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" target="_self" href="javascript:;" aria-label="Color Toggle">&nbsp;<i
                class="iconfont icon-dark" id="color-toggle-icon"></i>&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

    <div class="banner" id="banner" parallax=true
         style="background: url('/images/default.png') no-repeat center center;
           background-size: cover;">
      <div class="full-bg-img">
        <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
          <div class="page-header text-center fade-in-up">
            <span class="h2" id="subtitle" title="JUC学习笔记（五）Lock底层原理探究">
              
            </span>

            
              <div class="mt-3">
  
  
    <span class="post-meta">
      <i class="iconfont icon-date-fill" aria-hidden="true"></i>
      <time datetime="2022-03-10 11:39" pubdate>
        2022年3月10日 中午
      </time>
    </span>
  
</div>

<div class="mt-1">
  
    <span class="post-meta mr-2">
      <i class="iconfont icon-chart"></i>
      15k 字
    </span>
  

  
    <span class="post-meta mr-2">
      <i class="iconfont icon-clock-fill"></i>
      
      
      47 分钟
    </span>
  

  
  
    
      <!-- 不蒜子统计文章PV -->
      <span id="busuanzi_container_page_pv" style="display: none">
        <i class="iconfont icon-eye" aria-hidden="true"></i>
        <span id="busuanzi_value_page_pv"></span> 次
      </span>
    
  
</div>

            
          </div>

          
        </div>
      </div>
    </div>
  </header>

  <main>
    
      

<div class="container-fluid nopadding-x">
  <div class="row nomargin-x">
    <div class="d-none d-lg-block col-lg-2"></div>
    <div class="col-lg-8 nopadding-x-md">
      <div class="container nopadding-x-md" id="board-ctn">
        <div class="py-5" id="board">
          <article class="post-content mx-auto">
            <!-- SEO header -->
            <h1 style="display: none">JUC学习笔记（五）Lock底层原理探究</h1>
            
              <p class="note note-info">
                
                  本文最后更新于：3 个月前
                
              </p>
            
            <div class="markdown-body">
              <h1 id="Lock-底层原理探究"><a href="#Lock-底层原理探究" class="headerlink" title="Lock 底层原理探究"></a>Lock 底层原理探究</h1><h1 id="第一节-JMM"><a href="#第一节-JMM" class="headerlink" title="第一节 JMM"></a>第一节 JMM</h1><p>TIP</p>
<ol>
<li><p><strong>为什么要学这个 JMM？</strong></p>
<p>答：为了理解 volatile 关键词。</p>
</li>
<li><p><strong>为什么要学这个 volatile ？</strong></p>
<p>答：因为 volatile 是后面整个技术体系的基石之一。</p>
</li>
</ol>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-01.png?versionId=CAEQKRiBgIC_27LH.xciIDgzNmIyNzk2NDAxOTQzNTFiMDQ5NDk0ODE0YjQxOTk1" srcset="/img/loading.gif" lazyload alt="images"></p>
<h2 id="1、名词解释"><a href="#1、名词解释" class="headerlink" title="1、名词解释"></a>1、名词解释</h2><p>JMM 是 <strong>J</strong>ava <strong>M</strong>emory <strong>M</strong>odel 的缩写，意思是：Java 内存模型。</p>
<h2 id="2、产生背景"><a href="#2、产生背景" class="headerlink" title="2、产生背景"></a>2、产生背景</h2><h3 id="①高速缓存"><a href="#①高速缓存" class="headerlink" title="①高速缓存"></a>①高速缓存</h3><p>现代计算机 CPU 的运算处理能力比内存 I/O 读写能力高几个数量级。如果让 CPU 对内存进行等待那将是对 CPU 资源的巨大浪费。可是如果将内存换成能够满足 CPU 需求的存储介质造价会高到无法承受。</p>
<p>为了让二者能力匹配、协调工作，在 CPU 和内存之间再添加一层高速缓存（具体硬件系统中可能是三级缓存，这里不深究），就可以让 CPU 从高速缓存读取和保存数据，数据修改后再从高速缓存同步回内存。</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-02.png?versionId=CAEQKRiBgIC827LH.xciIDIyODVhZmNiYmEwYjQ0ZTU4ZDZlMGI3MDZiYjU3Y2M0" srcset="/img/loading.gif" lazyload alt="images"></p>
<h3 id="②缓存一致性协议"><a href="#②缓存一致性协议" class="headerlink" title="②缓存一致性协议"></a>②缓存一致性协议</h3><p>但是从上图我们很容易能发现问题：多个不同 CPU 核心都从主内存读取了同一个数据，又做了不同修改。那么同步会主内存的时候以哪个修改为准呢？这个问题有一个专门的名字：缓存一致性（Cache Coherence）。为了解决一致性的问题，需要各个处理器访问缓存时都要遵循一些协议，在读写时要根据协议来进行操作，这类协议有MSI、MESI（Illinois Protocol）、MOSI、Synapse、Firefly及Dragon Protocol等。</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-03.png?versionId=CAEQKRiBgIC627LH.xciIGNkMmQwMGM2NmNhMDQ5OTc4YTYzNzc4Mzk5NWFkNzdh" srcset="/img/loading.gif" lazyload alt="images"></p>
<h2 id="3、Java-内存模型"><a href="#3、Java-内存模型" class="headerlink" title="3、Java 内存模型"></a>3、Java 内存模型</h2><h3 id="①基本概念"><a href="#①基本概念" class="headerlink" title="①基本概念"></a>①基本概念</h3><p>对 Java 程序来说同样存在上面的问题。曾经同样的 Java 代码在不同的硬件平台上运行会出现计算结果不一致的情况。这就和不同硬件系统使用不同方式应对缓存不一致问题有关。</p>
<p>为了屏蔽系统和硬件的差异，让一套代码在不同平台下能到达相同的访问结果。JMM 从 Java 5 开始的 <strong>JSR-133</strong> 发布后，已经成熟和完善起来。关于 JSR 标准的介绍请看末尾：</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-04.png?versionId=CAEQKRiBgMC227LH.xciIDYwMmMxNTU2NWM3NDRjYjJiYTUxZmVmMDY0ZWU2Mzkz" srcset="/img/loading.gif" lazyload alt="images"></p>
<h3 id="②主内存"><a href="#②主内存" class="headerlink" title="②主内存"></a>②主内存</h3><p>主内存是各<strong>线程共享</strong>的内存区域。而 JVM 的内存结构中堆内存也是线程共享的。</p>
<h3 id="③本地内存"><a href="#③本地内存" class="headerlink" title="③本地内存"></a>③本地内存</h3><p>本地内存（也叫工作内存）是主内存是各<strong>线程私有</strong>的内存区域。而 JVM 的内存结构中栈内存是线程私有的。所以 JVM 内存结构和 JMM 内存模型既有关联有不完全等同。</p>
<h3 id="④作用"><a href="#④作用" class="headerlink" title="④作用"></a>④作用</h3><p>Java 内存模型（JMM）设计出来就是为了解决缓存一致性问题的，拆解开来说，缓存一致性涉及到三个具体问题：</p>
<ul>
<li>原子性</li>
<li>可见性</li>
<li>有序性</li>
</ul>
<h2 id="4、原子性概念"><a href="#4、原子性概念" class="headerlink" title="4、原子性概念"></a>4、原子性概念</h2><h3 id="①内部视角-微观"><a href="#①内部视角-微观" class="headerlink" title="①内部视角(微观)"></a>①内部视角(微观)</h3><p>如果一个操作是<strong>不可分割</strong>的，那么我们就可以说这个操作是原子操作。比如：</p>
<ul>
<li>a = 0; （a 非 long、非 double 类型） 这个操作不可分割，所以是原子操作。</li>
<li>a ++; 这个操作的本质是 a = a + 1 两步操作，可以分割，所以不是原子操作。</li>
</ul>
<p>非原子操作都会存在线程安全问题，需要使用同步技术（sychronized）或者锁（Lock）来让它变成一个原子操作。一个操作是原子操作，那么我们称它具有原子性。Java 的 concurrent 包下提供了一些原子类，比如：AtomicInteger、AtomicLong、AtomicReference 等。</p>
<h3 id="②外部视角-宏观"><a href="#②外部视角-宏观" class="headerlink" title="②外部视角(宏观)"></a>②外部视角(宏观)</h3><p>在 JMM 模型框架下，两个线程各自修改一个共享变量采用的办法是：各自读取到自己的本地内存中，执行计算，然后 flush 回主内存。这就很可能会发生后面操作把前面操作的结果覆盖的问题。这种情况下最终的计算结果肯定是错的。</p>
<p>这样的问题同样需要使用同步机制（synchronized 或 Lock）将修改共享内存中数据的操作封装为原子操作：前面操作完，后面再操作；保证后面的操作在前面操作结果的基础上进行计算。</p>
<p>封装后内部操作仍然是多个，不能说是不可分割的，但是它们作为一个整体不会被多个线程交替执行。</p>
<p>所以从外部视角、宏观视角来说，原子性的含义是：一段代码在<strong>逻辑</strong>上可以看做一个<strong>整体</strong>，多个线程执行这段代码不是交替执行。</p>
<h2 id="5、原子性举例"><a href="#5、原子性举例" class="headerlink" title="5、原子性举例"></a>5、原子性举例</h2><h3 id="①情景设定"><a href="#①情景设定" class="headerlink" title="①情景设定"></a>①情景设定</h3><ul>
<li>声明 int 类型的成员变量</li>
<li>初始值为 0</li>
<li>两个线程对这个数据各执行 100 次累加</li>
</ul>
<h3 id="②未同步"><a href="#②未同步" class="headerlink" title="②未同步"></a>②未同步</h3><h4 id="1-Java-代码"><a href="#1-Java-代码" class="headerlink" title="[1] Java 代码"></a>[1] Java 代码</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo11AtomicTest</span> </span>&#123;<br><br>    <span class="hljs-comment">// 声明成员变量作为操作对象</span><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> data = <span class="hljs-number">0</span>;<br><br>    <span class="hljs-comment">// 声明专门的方法执行累加操作</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">add</span><span class="hljs-params">()</span> </span>&#123;<br>        System.out.println(Thread.currentThread().getName() + <span class="hljs-string">&quot; data = &quot;</span> + ++data);<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;<br>        <span class="hljs-comment">// 创建线程共享对象</span><br>        Demo11AtomicTest demo = <span class="hljs-keyword">new</span> Demo11AtomicTest();<br><br>        <span class="hljs-comment">// 创建第一个线程执行累加操作</span><br>        <span class="hljs-keyword">new</span> Thread(()-&gt;&#123;<br>            <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">100</span>; i++) &#123;<br>                <span class="hljs-keyword">try</span> &#123;<br>                    TimeUnit.SECONDS.sleep(<span class="hljs-number">1</span>);&#125; <span class="hljs-keyword">catch</span> (InterruptedException e) &#123;&#125;<br>                demo.add();<br>            &#125;<br>        &#125;, <span class="hljs-string">&quot;thread-01&quot;</span>).start();<br><br>        <span class="hljs-comment">// 创建第二个线程执行累加操作</span><br>        <span class="hljs-keyword">new</span> Thread(()-&gt;&#123;<br>            <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">100</span>; i++) &#123;<br>                <span class="hljs-keyword">try</span> &#123;TimeUnit.SECONDS.sleep(<span class="hljs-number">1</span>);&#125; <span class="hljs-keyword">catch</span> (InterruptedException e) &#123;&#125;<br>                demo.add();<br>            &#125;<br>        &#125;, <span class="hljs-string">&quot;thread-02&quot;</span>).start();<br><br>    &#125;<br><br>&#125;<br></code></pre></td></tr></table></figure>



<h4 id="2-效果说明"><a href="#2-效果说明" class="headerlink" title="[2] 效果说明"></a>[2] 效果说明</h4><blockquote>
<p>thread-01 data = 168<br>thread-02 data = <strong>169</strong><br>thread-01 data = <strong>169</strong><br>thread-01 data = 170</p>
<p>……</p>
<p>thread-02 data = 177<br>thread-02 data = 178<br>thread-01 data = 179</p>
</blockquote>
<p>中间重复的数据非常能说明问题：</p>
<ul>
<li>读取数据：</li>
</ul>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-05.png?versionId=CAEQKRiBgMCx27LH.xciIGQ4OTI0ZGY2M2U2MDRkMzJhNTlmODcyMmVkM2UyMzYw" srcset="/img/loading.gif" lazyload alt="images"></p>
<ul>
<li>执行计算：</li>
</ul>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-06.png?versionId=CAEQKRiBgMCu27LH.xciIDIzYjM0MTNmODMxZjRhNWE4YjRmYTgzM2EwYmFhYzcx" srcset="/img/loading.gif" lazyload alt="images"></p>
<ul>
<li>thread-01 结果写回：</li>
</ul>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-07.png?versionId=CAEQKRiBgID.2bLH.xciIDRmOGI0YTc0NmJlMTQwNTliZWNiNGI2MGJiMzBjOTA4" srcset="/img/loading.gif" lazyload alt="images"></p>
<ul>
<li>thread-02 结果写回：</li>
</ul>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-08.png?versionId=CAEQKRiBgID72bLH.xciIDI0ODFjODMwYjY3ZTRkNTE4OTZlZDY0ZGE1Nzg1MmFk" srcset="/img/loading.gif" lazyload alt="images"></p>
<p>但是其实现在 2 号线程应该做的是从 169 + 1 变成 170。</p>
<h3 id="③使用-synchronized-同步"><a href="#③使用-synchronized-同步" class="headerlink" title="③使用 synchronized 同步"></a>③使用 synchronized 同步</h3><h4 id="1-修改-Java-代码"><a href="#1-修改-Java-代码" class="headerlink" title="[1]修改 Java 代码"></a>[1]修改 Java 代码</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// 将累加方法修改为同步方法</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">synchronized</span> <span class="hljs-keyword">void</span> <span class="hljs-title">add</span><span class="hljs-params">()</span> </span>&#123;<br>    System.out.println(Thread.currentThread().getName() + <span class="hljs-string">&quot; data = &quot;</span> + ++data);<br>&#125;<br></code></pre></td></tr></table></figure>



<h4 id="2-效果说明-1"><a href="#2-效果说明-1" class="headerlink" title="[2]效果说明"></a>[2]效果说明</h4><p>使用同步锁之后可以保证最终结果计算准确：</p>
<blockquote>
<p>thread-01 data = 198<br>thread-02 data = 199<br>thread-01 data = <strong>200</strong></p>
</blockquote>
<h3 id="④使用-AtomicInteger-累加"><a href="#④使用-AtomicInteger-累加" class="headerlink" title="④使用 AtomicInteger 累加"></a>④使用 AtomicInteger 累加</h3><h4 id="1-修改-Java-代码-1"><a href="#1-修改-Java-代码-1" class="headerlink" title="[1]修改 Java 代码"></a>[1]修改 Java 代码</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// 声明成员变量作为操作对象</span><br><span class="hljs-keyword">private</span> AtomicInteger data = <span class="hljs-keyword">new</span> AtomicInteger(<span class="hljs-number">0</span>);<br><br><span class="hljs-comment">// 累加方法还是非同步方法</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">add</span><span class="hljs-params">()</span> </span>&#123;<br>    System.out.println(Thread.currentThread().getName() + <span class="hljs-string">&quot; data = &quot;</span> + data.incrementAndGet());<br>&#125;<br></code></pre></td></tr></table></figure>



<h4 id="2-效果说明-2"><a href="#2-效果说明-2" class="headerlink" title="[2]效果说明"></a>[2]效果说明</h4><p>可以保证计算结果正确：</p>
<blockquote>
<p>thread-01 data = 194<br>thread-02 data = 193<br>thread-01 data = 195<br>thread-02 data = 196<br>thread-01 data = 197<br>thread-02 data = 198<br>thread-02 data = <strong>200</strong><br>thread-01 data = 199</p>
</blockquote>
<h2 id="6、同步锁和原子类的性能比较"><a href="#6、同步锁和原子类的性能比较" class="headerlink" title="6、同步锁和原子类的性能比较"></a>6、同步锁和原子类的性能比较</h2><h3 id="①情景设定-1"><a href="#①情景设定-1" class="headerlink" title="①情景设定"></a>①情景设定</h3><p>两个线程对同一个数据从 0 累加到 1000 万。数量大一些便于看到较为明显的效果，我们中间不执行线程睡眠就不会花很多时间。</p>
<h3 id="②同步锁"><a href="#②同步锁" class="headerlink" title="②同步锁"></a>②同步锁</h3><h4 id="1-Java-代码-1"><a href="#1-Java-代码-1" class="headerlink" title="[1] Java 代码"></a>[1] Java 代码</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo12PKSync</span> </span>&#123;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> data = <span class="hljs-number">0</span>;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">synchronized</span> <span class="hljs-keyword">void</span> <span class="hljs-title">add</span><span class="hljs-params">()</span> </span>&#123;<br>        data ++;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;<br>        Demo12PKSync demo = <span class="hljs-keyword">new</span> Demo12PKSync();<br><br>        <span class="hljs-keyword">new</span> Thread(()-&gt;&#123;<br>            <span class="hljs-keyword">long</span> beginTime = System.currentTimeMillis();<br><br>            <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">10000000</span>; i++) &#123;<br>                demo.add();<br>            &#125;<br><br>            <span class="hljs-keyword">long</span> endTime = System.currentTimeMillis();<br>            <span class="hljs-keyword">long</span> usedTime = endTime - beginTime;<br>            System.out.println(Thread.currentThread().getName() + <span class="hljs-string">&quot; usedTime = &quot;</span> + usedTime);<br><br>        &#125;, <span class="hljs-string">&quot;thread-01&quot;</span>).start();<br><br>        <span class="hljs-keyword">new</span> Thread(()-&gt;&#123;<br><br>            <span class="hljs-keyword">long</span> beginTime = System.currentTimeMillis();<br>            <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">10000000</span>; i++) &#123;<br>                demo.add();<br>            &#125;<br><br>            <span class="hljs-keyword">long</span> endTime = System.currentTimeMillis();<br>            <span class="hljs-keyword">long</span> usedTime = endTime - beginTime;<br>            System.out.println(Thread.currentThread().getName() + <span class="hljs-string">&quot; usedTime = &quot;</span> + usedTime);<br>        &#125;, <span class="hljs-string">&quot;thread-02&quot;</span>).start();<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>



<h4 id="2-效果"><a href="#2-效果" class="headerlink" title="[2]效果"></a>[2]效果</h4><blockquote>
<p>thread-01 usedTime = 628<br>thread-02 usedTime = 700</p>
</blockquote>
<h3 id="③原子类"><a href="#③原子类" class="headerlink" title="③原子类"></a>③原子类</h3><h4 id="1-Java-代码-2"><a href="#1-Java-代码-2" class="headerlink" title="[1] Java 代码"></a>[1] Java 代码</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo12PKAtomic</span> </span>&#123;<br><br>    <span class="hljs-keyword">private</span> AtomicInteger data = <span class="hljs-keyword">new</span> AtomicInteger(<span class="hljs-number">0</span>);<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">add</span><span class="hljs-params">()</span> </span>&#123;<br>        data.incrementAndGet();<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;<br>        Demo12PKAtomic demo = <span class="hljs-keyword">new</span> Demo12PKAtomic();<br><br>        <span class="hljs-keyword">new</span> Thread(()-&gt;&#123;<br>            <span class="hljs-keyword">long</span> beginTime = System.currentTimeMillis();<br><br>            <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">10000000</span>; i++) &#123;<br>                demo.add();<br>            &#125;<br><br>            <span class="hljs-keyword">long</span> endTime = System.currentTimeMillis();<br>            <span class="hljs-keyword">long</span> usedTime = endTime - beginTime;<br>            System.out.println(Thread.currentThread().getName() + <span class="hljs-string">&quot; usedTime = &quot;</span> + usedTime);<br><br>        &#125;, <span class="hljs-string">&quot;thread-01&quot;</span>).start();<br><br>        <span class="hljs-keyword">new</span> Thread(()-&gt;&#123;<br><br>            <span class="hljs-keyword">long</span> beginTime = System.currentTimeMillis();<br>            <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">10000000</span>; i++) &#123;<br>                demo.add();<br>            &#125;<br><br>            <span class="hljs-keyword">long</span> endTime = System.currentTimeMillis();<br>            <span class="hljs-keyword">long</span> usedTime = endTime - beginTime;<br>            System.out.println(Thread.currentThread().getName() + <span class="hljs-string">&quot; usedTime = &quot;</span> + usedTime);<br>        &#125;, <span class="hljs-string">&quot;thread-02&quot;</span>).start();<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>



<h4 id="2-效果-1"><a href="#2-效果-1" class="headerlink" title="[2]效果"></a>[2]效果</h4><blockquote>
<p>thread-02 usedTime = 233<br>thread-01 usedTime = 239</p>
</blockquote>
<p>性能的提升效果还是很明显的。原理我们会在后面结合 AQS 和 CAS 来说明。</p>
<h3 id="④只有一个线程时的同步锁"><a href="#④只有一个线程时的同步锁" class="headerlink" title="④只有一个线程时的同步锁"></a>④只有一个线程时的同步锁</h3><h4 id="1-Java-代码-3"><a href="#1-Java-代码-3" class="headerlink" title="[1] Java 代码"></a>[1] Java 代码</h4><p>在前面代码基础上去掉一个线程。</p>
<h4 id="2-效果-2"><a href="#2-效果-2" class="headerlink" title="[2]效果"></a>[2]效果</h4><blockquote>
<p>thread-01 usedTime = 283</p>
</blockquote>
<p>也一下子提升了很多，这说明底层具体执行的时候因为只有一个线程，所以没有膨胀到重量级锁。但是生产环境下并发量增大，线程一定会变多。synchronized 必然会膨胀为重量级锁。所以还是要视情况来减少 synchronized 的使用。</p>
<h2 id="7、可见性"><a href="#7、可见性" class="headerlink" title="7、可见性"></a>7、可见性</h2><h3 id="①示例代码"><a href="#①示例代码" class="headerlink" title="①示例代码"></a>①示例代码</h3><p>每个线程操作自己的本地内存，对其他线程是不可见的。看下面代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo15CanSeeTest</span> </span>&#123;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> data = <span class="hljs-number">100</span>;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getData</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> data;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setData</span><span class="hljs-params">(<span class="hljs-keyword">int</span> data)</span> </span>&#123;<br>        <span class="hljs-keyword">this</span>.data = data;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;<br><br>        Demo15CanSeeTest demo = <span class="hljs-keyword">new</span> Demo15CanSeeTest();<br><br>        <span class="hljs-keyword">new</span> Thread(()-&gt;&#123;<br>            <span class="hljs-keyword">while</span> (demo.getData() == <span class="hljs-number">100</span>) &#123;&#125;<br>            System.out.println(<span class="hljs-string">&quot;AAA 线程发现 data 新值：&quot;</span> + demo.getData());<br>        &#125;, <span class="hljs-string">&quot;AAA&quot;</span>).start();<br><br>        <span class="hljs-keyword">new</span> Thread(()-&gt;&#123;<br>            <span class="hljs-keyword">try</span> &#123;TimeUnit.SECONDS.sleep(<span class="hljs-number">1</span>);&#125; <span class="hljs-keyword">catch</span> (InterruptedException e) &#123;&#125;<br><br>            demo.setData(<span class="hljs-number">200</span>);<br>            System.out.println(<span class="hljs-string">&quot;BBB 线程修改 data，新值是：&quot;</span> + demo.getData());<br>        &#125;, <span class="hljs-string">&quot;BBB&quot;</span>).start();<br><br>    &#125;<br><br>&#125;<br></code></pre></td></tr></table></figure>



<p>运行效果：</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-09.png?versionId=CAEQKRiBgID62bLH.xciIDMxOTJkNjQ5YWFhYjQ0OWJhNzg4NjJiNTYzNjMyODU5" srcset="/img/loading.gif" lazyload alt="images"></p>
<p>可以看到，程序一直在运行着没有停止。这是因为 while (demo.getData() == 100) 循环条件始终成立。证明 AAA 线程看到的 data 值始终是旧值。</p>
<h3 id="②示例分析"><a href="#②示例分析" class="headerlink" title="②示例分析"></a>②示例分析</h3><h4 id="1-两个线程加载变量"><a href="#1-两个线程加载变量" class="headerlink" title="[1]两个线程加载变量"></a>[1]两个线程加载变量</h4><p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-10.png?versionId=CAEQKRiBgMD42bLH.xciIGI2Y2IxMjhhNzIwZDQ5YjZhNTJmZWI5NzgyYTE5YjYw" srcset="/img/loading.gif" lazyload alt="images"></p>
<h4 id="2-线程-B-修改变量"><a href="#2-线程-B-修改变量" class="headerlink" title="[2]线程 B 修改变量"></a>[2]线程 B 修改变量</h4><p>线程 B 首先在自己的本地内存修改数据：</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-11.png?versionId=CAEQKRiBgMDo2bLH.xciIGZmNDhiMDgxYTE1NzQwZGY5YzcxN2RmMDRmZDMwYjJk" srcset="/img/loading.gif" lazyload alt="images"></p>
<h4 id="3-线程-B-将新数据写回主内存"><a href="#3-线程-B-将新数据写回主内存" class="headerlink" title="[3]线程 B 将新数据写回主内存"></a>[3]线程 B 将新数据写回主内存</h4><p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-12.png?versionId=CAEQKRiCgMDq2bLH.xciIDliN2ZiOWM2NGZmMTQ4OTFiNmFiNDVlZjBmM2QwNWU2" srcset="/img/loading.gif" lazyload alt="images"></p>
<h4 id="4-问题核心"><a href="#4-问题核心" class="headerlink" title="[4]问题核心"></a>[4]问题核心</h4><p>线程 A 始终都是在从自己的本地内存获取数据，没有去读取主内存。</p>
<h2 id="8、有序性"><a href="#8、有序性" class="headerlink" title="8、有序性"></a>8、有序性</h2><h3 id="①指令重排序"><a href="#①指令重排序" class="headerlink" title="①指令重排序"></a>①指令重排序</h3><p>CPU 执行程序指令和 JVM 编译源程序之后，都会对指令做一定的重排序，目的是提高部分代码执行的效率。原则是重新排序后代码执行的结果和不重排执行的结果必须一样。</p>
<h3 id="②有序性概念"><a href="#②有序性概念" class="headerlink" title="②有序性概念"></a>②有序性概念</h3><p>从宏观和表面层次来看，我们感觉不到指令重排的存在，指令重排都是系统内部做的优化。保证无论是否指令重排，程序运行的结果都和预期一样，就是有序性。</p>
<h1 id="第二节-volatile-关键字"><a href="#第二节-volatile-关键字" class="headerlink" title="第二节 volatile 关键字"></a>第二节 volatile 关键字</h1><h2 id="1、英文单词"><a href="#1、英文单词" class="headerlink" title="1、英文单词"></a>1、英文单词</h2><p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-13.png?versionId=CAEQKRiBgMDn2bLH.xciIDRhZmZiMmFkNjI3MTRjODI4ZDNiYTYxMTJkYTE0MzA4" srcset="/img/loading.gif" lazyload alt="images"></p>
<h2 id="2、原子性"><a href="#2、原子性" class="headerlink" title="2、原子性"></a>2、原子性</h2><p>被 volatile 关键字修饰的变量是否满足原子性其实并不是由 volatile 本身来决定，而是和变量自身的数据类型有关。</p>
<h3 id="①示例代码-1"><a href="#①示例代码-1" class="headerlink" title="①示例代码"></a>①示例代码</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">VolatileAtomic</span> </span>&#123;<br><br><span class="hljs-comment">//        private volatile AtomicInteger data = new AtomicInteger(0);</span><br>            <span class="hljs-keyword">private</span> <span class="hljs-keyword">volatile</span> <span class="hljs-keyword">int</span> data = <span class="hljs-number">0</span>;<br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">add</span><span class="hljs-params">()</span> </span>&#123;<br><span class="hljs-comment">//            data.incrementAndGet();</span><br>            data++;<br><span class="hljs-comment">//            System.out.println(Thread.currentThread().getName() + &quot; data = &quot; + ++data);</span><br>        &#125;<br><br>        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> InterruptedException </span>&#123;<br>            VolatileAtomic demo = <span class="hljs-keyword">new</span> VolatileAtomic();<br>            CountDownLatch latch = <span class="hljs-keyword">new</span> CountDownLatch(<span class="hljs-number">2</span>);<br><br><br>            <span class="hljs-keyword">new</span> Thread(()-&gt;&#123;<br>                <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">1000000</span>; i++) &#123;<br>                    demo.add();<br>                &#125;<br>                latch.countDown();<br>            &#125;, <span class="hljs-string">&quot;AAA&quot;</span>).start();<br><br>            <span class="hljs-keyword">new</span> Thread(()-&gt;&#123;<br>                <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">1000000</span>; i++) &#123;<br>                    demo.add();<br>                &#125;<br>                latch.countDown();<br>            &#125;, <span class="hljs-string">&quot;BBB&quot;</span>).start();<br><br>            latch.await();<br>            System.out.println(demo.data);<br>        &#125;<br>&#125;<br></code></pre></td></tr></table></figure>



<h3 id="②运行效果"><a href="#②运行效果" class="headerlink" title="②运行效果"></a>②运行效果</h3><p>没有加到 2000000：</p>
<blockquote>
<p>985047</p>
</blockquote>
<p>但是把数据类型从 int 换成 AtomicInteger 即使不加 volatile 也能够保证原子性。</p>
<h3 id="③结论"><a href="#③结论" class="headerlink" title="③结论"></a>③结论</h3><p>volatile 关键字不提供原子性保证。</p>
<h2 id="3、可见性"><a href="#3、可见性" class="headerlink" title="3、可见性"></a>3、可见性</h2><p>volatile 写的内存语义：当<strong>写</strong>一个 volatile 变量时，JMM 会把该线程对应的本地内存中的变量值 <strong>flush 到主内存</strong>。</p>
<p>volatile 读的内存语义：当<strong>读</strong>一个 volatile 变量时，JMM 会把该线程对应的<strong>本地内存置为无效</strong>。线程接下来将<strong>从主内存中读</strong>取共享变量。</p>
<p>所以 volatile 关键字是能够保证可见性的。</p>
<p>大家可以运行下面的例子测试一下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo15CanSeeTest</span> </span>&#123;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">volatile</span> <span class="hljs-keyword">int</span> data = <span class="hljs-number">100</span>;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getData</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> data;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setData</span><span class="hljs-params">(<span class="hljs-keyword">int</span> data)</span> </span>&#123;<br>        <span class="hljs-keyword">this</span>.data = data;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;<br><br>        Demo15CanSeeTest demo = <span class="hljs-keyword">new</span> Demo15CanSeeTest();<br><br>        <span class="hljs-keyword">new</span> Thread(()-&gt;&#123;<br>            <span class="hljs-keyword">while</span> (demo.getData() == <span class="hljs-number">100</span>) &#123;&#125;<br>            System.out.println(<span class="hljs-string">&quot;AAA 线程发现 data 新值：&quot;</span> + demo.getData());<br>        &#125;, <span class="hljs-string">&quot;AAA&quot;</span>).start();<br><br>        <span class="hljs-keyword">new</span> Thread(()-&gt;&#123;<br>            <span class="hljs-keyword">try</span> &#123;TimeUnit.SECONDS.sleep(<span class="hljs-number">5</span>);&#125; <span class="hljs-keyword">catch</span> (InterruptedException e) &#123;&#125;<br><br>            demo.setData(<span class="hljs-number">200</span>);<br>            System.out.println(<span class="hljs-string">&quot;BBB 线程修改 data，新值是：&quot;</span> + demo.getData());<br>        &#125;, <span class="hljs-string">&quot;BBB&quot;</span>).start();<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>



<h2 id="4、有序性"><a href="#4、有序性" class="headerlink" title="4、有序性"></a>4、有序性</h2><p>volatile 确实是一个为数不多的能够从编码层面影响指令重排序的关键字。因为它可以在代码中添加内存屏障。</p>
<blockquote>
<p>所谓内存屏障，就是一种特殊的指令。底层指令中加入内存屏障，就会禁止一定范围内的内存重排。</p>
</blockquote>
<h3 id="①volatile-写"><a href="#①volatile-写" class="headerlink" title="①volatile 写"></a>①volatile 写</h3><p>在每个 volatile 写操作的前面插入一个 StoreStore 屏障。在每个 volatile 写操作的后面插入一个 StoreLoad 屏障。</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-14.png?versionId=CAEQKRiCgIDk2bLH.xciIGViNjZhNjkxYjNkZjQxY2Y4MWEzOTdhYWY4NjJmYjIz" srcset="/img/loading.gif" lazyload alt="images"></p>
<h3 id="②volatile-读"><a href="#②volatile-读" class="headerlink" title="②volatile 读"></a>②volatile 读</h3><p>在每个 volatile 读操作的后面插入一个 LoadLoad 屏障和一个 LoadStore 屏障。</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-15.png?versionId=CAEQKRiBgIDh2bLH.xciIDVjZmJlYmU0MDIwNzRhOGViYmUyNTZhYzYxMWJlNDgx" srcset="/img/loading.gif" lazyload alt="images"></p>
<h3 id="③结论-1"><a href="#③结论-1" class="headerlink" title="③结论"></a>③结论</h3><ul>
<li>微观层面：volatile 关键字能够提供有序性保证，但是从实际开发中编码层面感受不到。</li>
<li>宏观层面：volatile 关键字<strong>能够提供可见性</strong>保证，但是<strong>不能提供原子性</strong>保证。</li>
</ul>
<table>
<thead>
<tr>
<th>JMM特性</th>
<th>volatile能力</th>
</tr>
</thead>
<tbody><tr>
<td>原子性</td>
<td>无</td>
</tr>
<tr>
<td>可见性</td>
<td>有</td>
</tr>
<tr>
<td>有序性</td>
<td>有</td>
</tr>
</tbody></table>
<h2 id="5、补充"><a href="#5、补充" class="headerlink" title="5、补充"></a>5、补充</h2><p>volatile 关键词只能修饰成员变量：</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-16.png?versionId=CAEQKRiBgIDd2bLH.xciIDhlZjQzYmM5MDk0ZDRmZGY4Zjg0MzE5MmM1ZDkyOWE2" srcset="/img/loading.gif" lazyload alt="images"></p>
<h2 id="6、请谈谈你对-volatile-的理解。"><a href="#6、请谈谈你对-volatile-的理解。" class="headerlink" title="6、请谈谈你对 volatile 的理解。"></a>6、请谈谈你对 volatile 的理解。</h2><ul>
<li>内涵<ul>
<li>从 JMM 三大特性的角度来说明 volatile 的功能：<ul>
<li>原子性：没有</li>
<li>可见性：有</li>
<li>有序性：有</li>
</ul>
</li>
<li><strong>volatile 关键词最重要的功能就是为我们的程序提供可见性保证</strong></li>
</ul>
</li>
<li>外延<ul>
<li>从 volatile 在整个技术系统中的作用来说：<ul>
<li>volatile + CAS = 原子类的底层原理</li>
<li>volatile + CAS + 线程对象的双向链表 = AQS 的底层原理</li>
<li>AQS 是 JUC 中各种 API 底层用到的同步器的实现原理</li>
</ul>
</li>
</ul>
</li>
<li>扩展<ul>
<li>从 Lock 系列 API 扩展到传统的 synchronized 同步方式</li>
<li>从多线程的技术领域扩展到项目中多线程的实际应用</li>
</ul>
</li>
</ul>
<h1 id="第三节-CAS-机制"><a href="#第三节-CAS-机制" class="headerlink" title="第三节 CAS 机制"></a>第三节 CAS 机制</h1><h2 id="1、名称解释"><a href="#1、名称解释" class="headerlink" title="1、名称解释"></a>1、名称解释</h2><p>CAS：<strong>C</strong>ompare <strong>A</strong>nd <strong>S</strong>wap 比较并交换。</p>
<p>谁和谁比较？</p>
<p>为什么比较完了才能交换？</p>
<p>谁和谁交换？</p>
<p>这东西有什么用？</p>
<p>下面我们一一来解释。</p>
<h2 id="2、工作机制"><a href="#2、工作机制" class="headerlink" title="2、工作机制"></a>2、工作机制</h2><h3 id="①Unsafe类"><a href="#①Unsafe类" class="headerlink" title="①Unsafe类"></a>①Unsafe类</h3><h4 id="1-引入"><a href="#1-引入" class="headerlink" title="[1]引入"></a>[1]引入</h4><p>原子类 AtomicInteger 中就大量用到了 CAS 机制，compareAndSet(int expect, int update); 方法就是其中的典型代表。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">compareAndSet</span><span class="hljs-params">(<span class="hljs-keyword">int</span> expect, <span class="hljs-keyword">int</span> update)</span> </span>&#123;<br>    <span class="hljs-keyword">return</span> unsafe.compareAndSwapInt(<span class="hljs-keyword">this</span>, valueOffset, expect, update);<br>&#125;<br></code></pre></td></tr></table></figure>



<p>从源码中我们可以看出，compareAndSet(int expect, int update); 方法里面其实是调用了 Unsafe 类的 compareAndSwapInt() 方法。</p>
<p>Unsafe.compareAndSwapInt() 方法的源码如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">native</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">compareAndSwapInt</span><span class="hljs-params">(Object var1, <span class="hljs-keyword">long</span> var2, <span class="hljs-keyword">int</span> var4, <span class="hljs-keyword">int</span> var5)</span></span>;<br></code></pre></td></tr></table></figure>



<p>很明显，这是一个本地方法。那 Unsafe 类是做什么的呢？</p>
<h4 id="2-介绍"><a href="#2-介绍" class="headerlink" title="[2]介绍"></a>[2]介绍</h4><p>C/C++ 代码可以直接操作内存空间。而 Java 程序屏蔽了对内存空间的直接访问，简化了代码复杂度，提高了安全性。但是凡事都有例外，Unsafe 类在一定程度上可以看作是一个可以用来操作内存空间的 Java 类。</p>
<p>正是因为使用 Unsafe 类可以直接操作内存，所以它的名字叫 Unsafe，也就是『<strong>危险</strong>』的意思——常规业务功能的开发中不能直接操作内存，这是非常危险的操作。</p>
<p>所以这里的 Unsafe 并不是指线程不安全。我们这里关注的是它提供的 CAS 方法。</p>
<h3 id="②举例说明"><a href="#②举例说明" class="headerlink" title="②举例说明"></a>②举例说明</h3><h4 id="1-内存初始状态"><a href="#1-内存初始状态" class="headerlink" title="[1]内存初始状态"></a>[1]内存初始状态</h4><ul>
<li>内存空间地址：0x00FA</li>
<li>内存空间数据值：5</li>
</ul>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-17.png?versionId=CAEQKRiBgMCn2LLH.xciIDE0ZDYyNGMyNzYxNzQ0MzY5OTRmYTcwMjE0YjdjM2U5" srcset="/img/loading.gif" lazyload alt="images_cas"></p>
<h4 id="2-尝试修改成功"><a href="#2-尝试修改成功" class="headerlink" title="[2]尝试修改成功"></a>[2]尝试修改成功</h4><p>CAS 机制修改数据必须提供内存空间地址以找到要修改的数据。提供旧值用来和内存实际值进行比较。提供新值作为修改后的值。</p>
<ul>
<li>内存空间地址：0x00FA</li>
<li>内存空间数据值：<strong>5</strong></li>
<li>修改者提供的旧值（expected value）：<strong>5</strong></li>
<li>修改者提供的新值（update value）：10</li>
</ul>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-18.png?versionId=CAEQKRiBgICn2LLH.xciIDY4ZjQ1MDRmZjBmMzRhNDlhZTlhZjUwMmU1NGUxOTkz" srcset="/img/loading.gif" lazyload alt="images_cas"></p>
<h4 id="3-尝试修改失败"><a href="#3-尝试修改失败" class="headerlink" title="[3]尝试修改失败"></a>[3]尝试修改失败</h4><p>如果修改者提供的旧值与内存实际值不相等，那么 CAS 机制将禁止修改数据。</p>
<ul>
<li>内存空间地址：0x00FA</li>
<li>内存空间数据值：<strong>7</strong></li>
<li>修改者提供的旧值（expected value）：<strong>5</strong></li>
<li>修改者提供的新值（update value）：10</li>
</ul>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-19.png?versionId=CAEQKRiBgMCh2LLH.xciIGFmNDU5ZTVmZjY2ZTRmNDdhOWZlYzExNWE3Y2MyMmY0" srcset="/img/loading.gif" lazyload alt="images_cas"></p>
<h4 id="4-自旋"><a href="#4-自旋" class="headerlink" title="[4]自旋"></a>[4]自旋</h4><p>修改被禁止，但操作不会结束。CAS 机制会引导修改者读取当前内存值，然后再次尝试修改。</p>
<ul>
<li>读取内存值作为旧值：</li>
</ul>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-20.png?versionId=CAEQKRiCgMCO2LLH.xciIDYxMTI3NzBiY2JjZTRlZjJhNzIxMjExMDAxNzViZDM4" srcset="/img/loading.gif" lazyload alt="images_cas"></p>
<ul>
<li>再次尝试修改：</li>
</ul>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-21.png?versionId=CAEQKRiBgMCG2LLH.xciIGE4MmVjMTBhMzk5OTQ0NGE4Y2ViMjQyYWViYTMyMGNj" srcset="/img/loading.gif" lazyload alt="images_cas"></p>
<p>TIP</p>
<p>注意：读取内存值之后的第二次尝试修改也不一定修改成功。自旋可能会执行多次。</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-22.png?versionId=CAEQKRiBgICG2LLH.xciIGZmMDAwY2U4NWJlMTQ4ZjRhNmMzZGFjOTkxOWVlOGRk" srcset="/img/loading.gif" lazyload alt="images_cas"></p>
<h3 id="③配合-volatile"><a href="#③配合-volatile" class="headerlink" title="③配合 volatile"></a>③配合 volatile</h3><p>思考一个问题：我们前面提到的内存空间是工作内存还是主内存呢？很明显，应该是主内存。如果是在工作内存中一个线程内部自己和自己玩也就没必要整这些了，所以这里的内存空间指的是主内存。</p>
<p>但是每个线程修改数据又都是在工作内存完成的，修改完成执行 store 指令才会同步到主内存，执行 write 指令才会设置到对应变量中。</p>
<p>所以 CAS 操作通常都会配合 volatile 关键字：将 CAS 要操作的变量使用 volatile 修饰，实现可见性效果。</p>
<p>这一点我们看 AtomicInteger 类就可以发现：</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-23.png?versionId=CAEQKRiBgICL2LLH.xciIGJlM2RlMDQwZGFmODQxZWFhNjlkMTA1YTEwMjc4YjU3" srcset="/img/loading.gif" lazyload alt="images_cas"></p>
<p>所以 AtomicInteger 等原子类可以看成是 CAS 机制配合 volatile 实现非阻塞同步的经典案例。</p>
<h2 id="3、非阻塞同步"><a href="#3、非阻塞同步" class="headerlink" title="3、非阻塞同步"></a>3、非阻塞同步</h2><p>前面我们比较过 AtomicInteger 和 synchronized 两种方案实现原子性操作的性能差距，AtomicInteger 方式对比 synchronized 方式性能优势非常明显。</p>
<p>那 AtomicInteger 是如何做到既保证原子性（同步），又能够达到非常高的效率呢？</p>
<p>原因是：</p>
<ul>
<li>使用 CAS 机制修改数据不需要对代码块加同步锁，各线程通过自旋的方式不断尝试修改，<strong>线程不会被阻塞</strong>。</li>
<li>配合 volatile 关键字使各个线程直接操作主内存避免了数据不一致。</li>
</ul>
<p>所以 CAS 配合 volatile 不需要阻塞线程就能够实现同步效果，性能自然就会比 synchronized 更好。我们把这种机制称为：<strong>非阻塞同步</strong>。</p>
<p>当然，这种机制也并不能完全取代同步锁。因为 CAS 针对的是内存中的一个具体数据，无法对一段代码实现同步效果。</p>
<h2 id="4、CAS-测试代码"><a href="#4、CAS-测试代码" class="headerlink" title="4、CAS 测试代码"></a>4、CAS 测试代码</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// 1、创建 Integer 的原子类对象，设定初始值为 5</span><br>AtomicInteger atomicInteger = <span class="hljs-keyword">new</span> AtomicInteger(<span class="hljs-number">5</span>);<br><br><span class="hljs-comment">// 2、尝试修改</span><br><span class="hljs-comment">// ①基于旧值 5 修改</span><br><span class="hljs-comment">// updateResult = true 当前值 = 666</span><br><span class="hljs-keyword">boolean</span> updateResult = atomicInteger.compareAndSet(<span class="hljs-number">5</span>, <span class="hljs-number">666</span>);<br>System.out.println(<span class="hljs-string">&quot;updateResult = &quot;</span> + updateResult + <span class="hljs-string">&quot; 当前值 = &quot;</span> + atomicInteger.get());<br><br><span class="hljs-comment">// ②基于旧值 5 修改</span><br><span class="hljs-comment">// updateResult = false 当前值 = 666</span><br>updateResult = atomicInteger.compareAndSet(<span class="hljs-number">5</span>, <span class="hljs-number">777</span>);<br>System.out.println(<span class="hljs-string">&quot;updateResult = &quot;</span> + updateResult + <span class="hljs-string">&quot; 当前值 = &quot;</span> + atomicInteger.get());<br><br><span class="hljs-comment">// ③基于旧值 666 修改</span><br><span class="hljs-comment">// updateResult = true 当前值 = 888</span><br>updateResult = atomicInteger.compareAndSet(<span class="hljs-number">666</span>, <span class="hljs-number">888</span>);<br>System.out.println(<span class="hljs-string">&quot;updateResult = &quot;</span> + updateResult + <span class="hljs-string">&quot; 当前值 = &quot;</span> + atomicInteger.get());<br></code></pre></td></tr></table></figure>



<p>打印结果：</p>
<blockquote>
<p>修改结果：true 当前值：666<br>修改结果：false 当前值：666<br>修改结果：true 当前值：777</p>
</blockquote>
<h2 id="5、ABA-问题"><a href="#5、ABA-问题" class="headerlink" title="5、ABA 问题"></a>5、ABA 问题</h2><p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-24.png?versionId=CAEQKRiBgICN2LLH.xciIGM5ZTA1MDJhMTMzMDQ1ODQ5Y2M2NTg0YTBjNGEzZmI0" srcset="/img/loading.gif" lazyload alt="images_cas"></p>
<p>ABA 问题本质：一个原本不允许的操作，因为数据发生了变化，又允许操作了。但是 ABA 问题虽然存在，但如果只修改一个值在简单计算的场景下应该是没有问题的。当然如果确实涉及到复杂的业务逻辑还是要注意一下。</p>
<h2 id="6、CAS-和乐观锁"><a href="#6、CAS-和乐观锁" class="headerlink" title="6、CAS 和乐观锁"></a>6、CAS 和乐观锁</h2><p>CAS 机制可以看做是乐观锁理念的一种具体实现。但是又<strong>不完整</strong>。因为乐观锁的具体实现通常是需要维护版本号的，但是 CAS 机制中并不包含版本号——如果有版本号辅助就不会有 ABA 问题了。</p>
<h2 id="7、从-JMM-三大特性角度看原子类"><a href="#7、从-JMM-三大特性角度看原子类" class="headerlink" title="7、从 JMM 三大特性角度看原子类"></a>7、从 JMM 三大特性角度看原子类</h2><p>前面我们看到 AtomicInteger 类是 CAS 机制和 volatile 关键字的整合，所以它的缓存一致性效果是二者的综合：</p>
<ul>
<li>原子性：满足。一方面前面我们已经测试过了，还有就是——你看人家这个类叫什么名字啊喂！</li>
<li>有序性：满足。由 volatile 关键字保证有序性。</li>
<li>可见性：满足。由 volatile 关键字保证可见性。</li>
</ul>
<p>结论：单纯使用使用原子类执行并发操作时，<strong>能够保证线程安全</strong>，而且<strong>性能很好</strong>。</p>
<h1 id="第四节-AQS"><a href="#第四节-AQS" class="headerlink" title="第四节 AQS"></a>第四节 AQS</h1><h2 id="1、AQS-简介"><a href="#1、AQS-简介" class="headerlink" title="1、AQS 简介"></a>1、AQS 简介</h2><p>首先来认识一个<strong>抽象类</strong>：</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-25.png?versionId=CAEQKRiBgMD017LH.xciIDhiNjk4YjhkNzU4NTRjOGFhZWZlNDcyMTI0NzYyYzZi" srcset="/img/loading.gif" lazyload alt="images"></p>
<p>根据类的名字 AbstractQueuedSynchronizer 我们姑且可以翻译为：抽象的队列式同步器。AQS 定义了一套多线程访问共享资源的<strong>同步器框架</strong>，许多同步类实现都依赖于它。</p>
<p>它维护了一个 volatile int state（代表共享资源）和一个 FIFO 线程等待队列（多线程争用资源被阻塞时会进入此队列）。这里 volatile 是核心关键词。state 的访问方式有三种：</p>
<ul>
<li>getState()</li>
<li>setState()</li>
<li>compareAndSetState()</li>
</ul>
<p>AQS定义两种资源共享方式：Exclusive（独占，只有一个线程能执行，如ReentrantLock）和 Share（共享，多个线程可同时执行，如 Semaphore、CountDownLatch 等。</p>
<p>TIP</p>
<ul>
<li>独占锁：排斥所有其它锁，例如：写锁。</li>
<li>共享锁：共享锁之间不排斥，排斥独占锁，例如：读锁。</li>
</ul>
<p>注意：如果是同一个线程对同一个对象加锁，那么它可以在加了独占锁之后继续加共享锁，或者，在加了共享锁之后继续加独占锁。所以上面所说的排斥是指线程之间。</p>
<h2 id="2、AQS-核心方法介绍"><a href="#2、AQS-核心方法介绍" class="headerlink" title="2、AQS 核心方法介绍"></a>2、AQS 核心方法介绍</h2><p>不同的自定义同步器争用共享资源的方式也不同。自定义同步器在实现时只需要实现共享资源 <strong>state 的获取与释放</strong>方式即可，至于具体线程等待队列的维护（如获取资源失败入队/唤醒出队等），AQS已经在顶层实现好了。自定义同步器实现时主要实现以下几种方法：</p>
<table>
<thead>
<tr>
<th>方法名</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>boolean isHeldExclusively()</td>
<td>该线程是否正在独占资源。只有用到 condition 才需要去重写它。</td>
</tr>
<tr>
<td>boolean tryAcquire(int)</td>
<td>尝试以独占方式获取资源，成功则返回true，失败则返回false。 int 类型的参数是用来累加 state 的</td>
</tr>
<tr>
<td>boolean tryRelease(int)</td>
<td>尝试以独占方式释放资源，成功则返回true，失败则返回false。 int 类型的参数是用来从 state 中减去的</td>
</tr>
<tr>
<td>int tryAcquireShared(int)</td>
<td>尝试以共享方式获取资源。 返回负数：获取失败 返回正数：获取成功且有剩余资源 返回0：获取成功但没有剩余资源</td>
</tr>
<tr>
<td>boolean tryReleaseShared(int)</td>
<td>尝试以共享方式释放资源， 如果释放后允许唤醒后续等待结点返回 true，否则返回 false。</td>
</tr>
</tbody></table>
<h1 id="附录：JSR305标准相关注解"><a href="#附录：JSR305标准相关注解" class="headerlink" title="附录：JSR305标准相关注解"></a>附录：JSR305标准相关注解</h1><h2 id="1、从JSR说起"><a href="#1、从JSR说起" class="headerlink" title="1、从JSR说起"></a>1、从JSR说起</h2><h3 id="①JCP"><a href="#①JCP" class="headerlink" title="①JCP"></a>①JCP</h3><p>JCP（Java Community Process) 是一个由SUN公司发起的，开放的国际组织。主要由Java开发者以及被授权者组成，负责Java技术规范维护，Java技术发展和更新。</p>
<p>JCP官网地址：<a target="_blank" rel="noopener" href="https://jcp.org/en/home/index">https://jcp.org/en/home/index</a></p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC05-26.png?versionId=CAEQKRiBgMCF2LLH.xciIDUzOTgzNDU4YzZjMDQ3OGRiNzc4YjhmYTI0YTA1NjE5" srcset="/img/loading.gif" lazyload alt="./images"></p>
<h3 id="②JSR"><a href="#②JSR" class="headerlink" title="②JSR"></a>②JSR</h3><p>JSR 的全称是：Java Specification Request，意思是 Java 规范提案。谁向谁提案呢？任何人都可以向 JCP (Java Community Process) 提出新增一个标准化技术规范的正式请求。JSR已成为Java界的一个重要标准。登录<a target="_blank" rel="noopener" href="https://jcp.org/en/home/index"> JCP 官网 (opens new window)</a>可以查看<a target="_blank" rel="noopener" href="https://jcp.org/en/jsr/all">所有 JSR 标准 (opens new window)</a>。</p>
<h2 id="2、JSR-305"><a href="#2、JSR-305" class="headerlink" title="2、JSR 305"></a>2、JSR 305</h2><p>JSR 305: Annotations for Software Defect Detection</p>
<p>This JSR will work to develop standard annotations (such as @NonNull) that can be applied to Java programs to assist tools that detect software defects.</p>
<p>主要功能：使用注解（例如@NonNull等等）协助开发者侦测软件缺陷。</p>
<p>Spring 从 5.0 版本开始支持了 JSR 305 规范中涉及到的相关注解。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> org.springframework.lang;<br><br><span class="hljs-keyword">import</span> java.lang.annotation.Documented;<br><span class="hljs-keyword">import</span> java.lang.annotation.ElementType;<br><span class="hljs-keyword">import</span> java.lang.annotation.Retention;<br><span class="hljs-keyword">import</span> java.lang.annotation.RetentionPolicy;<br><span class="hljs-keyword">import</span> java.lang.annotation.Target;<br><br><span class="hljs-keyword">import</span> javax.annotation.Nonnull;<br><span class="hljs-keyword">import</span> javax.annotation.meta.TypeQualifierNickname;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * A common Spring annotation to declare that annotated elements cannot be &#123;<span class="hljs-doctag">@code</span> null&#125;.</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * &lt;p&gt;Leverages JSR-305 meta-annotations to indicate nullability in Java to common</span><br><span class="hljs-comment"> * tools with JSR-305 support and used by Kotlin to infer nullability of Spring API.</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * &lt;p&gt;Should be used at parameter, return value, and field level. Method overrides should</span><br><span class="hljs-comment"> * repeat parent &#123;<span class="hljs-doctag">@code</span> <span class="hljs-doctag">@NonNull</span>&#125; annotations unless they behave differently.</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * &lt;p&gt;Use &#123;<span class="hljs-doctag">@code</span> <span class="hljs-doctag">@NonNullApi</span>&#125; (scope = parameters + return values) and/or &#123;<span class="hljs-doctag">@code</span> <span class="hljs-doctag">@NonNullFields</span>&#125;</span><br><span class="hljs-comment"> * (scope = fields) to set the default behavior to non-nullable in order to avoid annotating</span><br><span class="hljs-comment"> * your whole codebase with &#123;<span class="hljs-doctag">@code</span> <span class="hljs-doctag">@NonNull</span>&#125;.</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> Sebastien Deleuze</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> Juergen Hoeller</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@since</span> 5.0</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@see</span> NonNullApi</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@see</span> NonNullFields</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@see</span> Nullable</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@Target(&#123;ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD&#125;)</span><br><span class="hljs-meta">@Retention(RetentionPolicy.RUNTIME)</span><br><span class="hljs-meta">@Documented</span><br><span class="hljs-meta">@Nonnull</span><br><span class="hljs-meta">@TypeQualifierNickname</span><br><span class="hljs-keyword">public</span> <span class="hljs-meta">@interface</span> NonNull &#123;<br>&#125;<br></code></pre></td></tr></table></figure>



<h2 id="3、相关注解"><a href="#3、相关注解" class="headerlink" title="3、相关注解"></a>3、相关注解</h2><table>
<thead>
<tr>
<th>注解名称</th>
<th>含义</th>
<th>可标记位置</th>
</tr>
</thead>
<tbody><tr>
<td>@Nullable</td>
<td>可以为空</td>
<td>@Target({ElementType.<strong>METHOD</strong>, ElementType.<strong>PARAMETER</strong>, ElementType.<strong>FIELD</strong>})</td>
</tr>
<tr>
<td>@NonNull</td>
<td>不应为空</td>
<td>@Target({ElementType.<strong>METHOD</strong>, ElementType.<strong>PARAMETER</strong>, ElementType.<strong>FIELD</strong>})</td>
</tr>
<tr>
<td>@NonNullFields</td>
<td>在特定包下的字段不应为空</td>
<td>@Target(ElementType.<strong>PACKAGE</strong>) @TypeQualifierDefault(ElementType.<strong>FIELD</strong>)</td>
</tr>
<tr>
<td>@NonNullApi</td>
<td>参数和方法返回值不应为空</td>
<td>@Target(ElementType.<strong>PACKAGE</strong>) @TypeQualifierDefault({ElementType.<strong>METHOD</strong>, ElementType.<strong>PARAMETER</strong>})</td>
</tr>
</tbody></table>

            </div>
            <hr>
            <div>
              <div class="post-metas mb-3">
                
                  <div class="post-meta mr-3">
                    <i class="iconfont icon-category"></i>
                    
                      <a class="hover-with-bg" href="/categories/JUC/">JUC</a>
                    
                  </div>
                
                
                  <div class="post-meta">
                    <i class="iconfont icon-tags"></i>
                    
                      <a class="hover-with-bg" href="/tags/JUC/">JUC</a>
                    
                  </div>
                
              </div>
              
                <p class="note note-warning">
                  
                    本博客目前大部分文章都是参考尚硅谷或者马士兵教育的学习资料！<a href="http://www.atguigu.com/" rel="nofollow noopener"官网地址！</a> 
                  
                </p>
              
              
                <div class="post-prevnext">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/2022/03/14/MySQL-%E6%9E%B6%E6%9E%84%E5%BC%95%E6%93%8E/">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">MySQL-架构引擎</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/2022/03/10/JUC04-scenario/">
                        <span class="hidden-mobile">JUC学习笔记（四）特定场所解决方案</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
              <!-- Comments -->
              <article class="comments" id="comments" lazyload>
                
                  
                
                

              </article>
            
          </article>
        </div>
      </div>
    </div>
    
      <div class="d-none d-lg-block col-lg-2 toc-container" id="toc-ctn">
        <div id="toc">
  <p class="toc-header"><i class="iconfont icon-list"></i>&nbsp;目录</p>
  <div class="toc-body" id="toc-body"></div>
</div>

      </div>
    
  </div>
</div>

<!-- Custom -->


    

    
      <a id="scroll-top-button" aria-label="TOP" href="#" role="button">
        <i class="iconfont icon-arrowup" aria-hidden="true"></i>
      </a>
    

    
      <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v"
                 for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>
    

    
  </main>

  <footer class="text-center mt-5 py-3">

  <div class="footer-content">
     <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><span>Hexo</span></a> <i class="iconfont icon-love"></i> <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener"><span>Fluid</span></a> 
	<!--《添加网站运行时间 -->
<br/>

<span id="timeDate">载入天数...</span><span id="times">载入时分秒...</span>
<script>
var now = new Date(); 

function createtime() {
    //此处修改你的建站时间或者网站上线时间
    var grt = new Date('11/02/2021 21:39:00');
    now.setTime(now.getTime() + 250);
    days = (now - grt) / 1000 / 60 / 60 / 24;

    dnum = Math.floor(days);
    hours = (now - grt) / 1000 / 60 / 60 - (24 * dnum);
    hnum = Math.floor(hours);
    if (String(hnum).length == 1) {
        hnum = "0" + hnum;
    }
    minutes = (now - grt) / 1000 / 60 - (24 * 60 * dnum) - (60 * hnum);
    mnum = Math.floor(minutes);
    if (String(mnum).length == 1) {
        mnum = "0" + mnum;
    }
    seconds = (now - grt) / 1000 - (24 * 60 * 60 * dnum) - (60 * 60 * hnum) - (60 * mnum);
    snum = Math.round(seconds);
    if (String(snum).length == 1) {
        snum = "0" + snum;
    }
    document.getElementById("timeDate").innerHTML = " 本站已各种夹缝中安全运行 " + dnum + " 天 ";
    document.getElementById("times").innerHTML = hnum + " 小时 " + mnum + " 分 " + snum + " 秒";
}
setInterval("createtime()", 250);
</script>

<!-- 添加网站运行时间》-->
  </div>
  
  <div class="statistics">
    
    

    
      
        <!-- 不蒜子统计PV -->
        <span id="busuanzi_container_site_pv" style="display: none">
            总访问量 
            <span id="busuanzi_value_site_pv"></span>
             次
          </span>
      
      
        <!-- 不蒜子统计UV -->
        <span id="busuanzi_container_site_uv" style="display: none">
            总访客数 
            <span id="busuanzi_value_site_uv"></span>
             人
          </span>
      
    
  </div>


  

  
</footer>


  <!-- SCRIPTS -->
  
  <script  src="https://cdn.jsdelivr.net/npm/nprogress@0/nprogress.min.js" ></script>
  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/nprogress@0/nprogress.min.css" />

  <script>
    NProgress.configure({"showSpinner":false,"trickleSpeed":100})
    NProgress.start()
    window.addEventListener('load', function() {
      NProgress.done();
    })
  </script>


<script  src="https://cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js" ></script>
<script  src="https://cdn.jsdelivr.net/npm/bootstrap@4/dist/js/bootstrap.min.js" ></script>
<script  src="/js/events.js" ></script>
<script  src="/js/plugins.js" ></script>

<!-- Plugins -->


  <script  src="/js/local-search.js" ></script>



  
    <script  src="/js/img-lazyload.js" ></script>
  



  



  
    <script  src="https://cdn.jsdelivr.net/npm/tocbot@4/dist/tocbot.min.js" ></script>
  
  
    <script  src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3/dist/jquery.fancybox.min.js" ></script>
  
  
    <script  src="https://cdn.jsdelivr.net/npm/anchor-js@4/anchor.min.js" ></script>
  
  
    <script defer src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js" ></script>
  



  <script defer src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" ></script>




  <script  src="https://cdn.jsdelivr.net/npm/typed.js@2/lib/typed.min.js" ></script>
  <script>
    (function (window, document) {
      var typing = Fluid.plugins.typing;
      var title = document.getElementById('subtitle').title;
      
      typing(title)
      
    })(window, document);
  </script>















<!-- 主题的启动项 保持在最底部 -->
<script  src="/js/boot.js" ></script>


</body>
</html>
